package projeto;

import grafoS.Adjacencia;
import grafoS.GraphList;
import grafoS.Graph;
import grafoS.Vertice;
import static java.lang.Thread.sleep;
import java.util.ArrayList;
import javafx.application.Platform;
import javafx.scene.control.TabPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;

/**
 * Gcol is a program to help users to learn a little about graph coloring, in
 * this software, you can learn some coloring algorithms, and add your own
 * algorithm for coloring.You can also learn BFS and DFS search. This tool, also
 * support the .col format from DIMACS (Center for Discrete Mathematics and
 * Theoretical Computer Science), so you can import a big graph and use all the
 * algorithms. Copyright (C) <2015> Clóvis Daniel Souza Silva, Samuel Silva de
 * Souza, Professor Leonardo Sampaio Rocha.
 * 
* This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
* This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
* You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 * contact: projetoGrafos@gmail.com
 */
/**
 *
 * @author Daniel.
 * @author Samuel.
 */
/**
 * This class, extends thread, because we'll need a thread to use sleep when
 * coloring, this way, we can see the step-by-step DFS(in portuguese Busca Por
 * Profundidade). In this class, we have a huge parameters because we'll use
 * some elements of the interface, like circles, text area, tab pane, we'll also
 * need the graph from the class Grafo, the int v to know where to start the
 * search, and the arrayList where we put the string for the console.
 */
public class BuscaProfundidade extends Thread {

    private boolean dimacsFile;
    private String texto = "\nVisit Order: ";
    private int tempo = 0, vertice = 0;
    public int tabExecutando;
    private String textoAnterior;
    private GraphList listaAdjacencia;
    private TabPane tabPane;
    private ArrayList<String> stringConsole;
    private ArrayList<Integer> permissaoTab;
    private ArrayList<ArrayList<Circle>> vertices;
    private javafx.scene.control.TextArea console;

    /**
     * This is the constructor, where we recive all the parameters from the
     * "Controle" class
     *
     *
     * @see Controlev2
     * @param v represents the vertex to start the DFS.
     * @param lA represents the adjacency list.
     * @param tP represents the current tab.
     * @param sC keep the record of the tasks in console.
     * @param pT the valor of permission, which is used to make exceptions for
     * each function.
     * @param listaVertices a list with all the circles in the canvas, we'll use
     * to make a visible step-by-step of DFS.
     * @param c we'll receive the console to print the visit order.
     * @param dF if it's true, means that there's no drawing.
     */
    public BuscaProfundidade(int v, GraphList lA, TabPane tP, ArrayList<String> sC,
            ArrayList<Integer> pT, ArrayList<ArrayList<Circle>> listaVertices, javafx.scene.control.TextArea c, boolean dF) {
        vertice = v;
        listaAdjacencia = lA;
        tabPane = tP;
        stringConsole = sC;
        permissaoTab = pT;
        vertices = listaVertices;
        console = c;
        dimacsFile = dF;
    }

    @Override
    public void run() {
        tabExecutando = tabPane.getSelectionModel().getSelectedIndex();
        textoAnterior = stringConsole.get(tabExecutando);
        dfs(listaAdjacencia);
    }
    /**/

    /**
     * Here, we will start the dfs, First, we set all vertex to white(branco in
     * portuguense) And then we take the integer vertice and start the dfs.
     *
     * @param g the list of adjacency.
     */
    public void dfs(GraphList g) {

        for (int i = 0; i < g.getV().length; i++) {
            g.getV()[i].setCor("branco");
            g.getV()[i].setPi(null);
        }

        int i = vertice;
        if (g.getV()[i].getCor().equals("branco")) {
            this.dfsvisit(g, g.getV()[i]);
        }

        try {
            if (dimacsFile == false) {
                sleep(3000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Platform.runLater(() -> toWhite());
        permissaoTab.set(tabExecutando, 0);
        Platform.runLater(() -> tabPane.getTabs().get(tabExecutando).getContent().setDisable(false));
    }

    /**
     * this method recives the graph with the current collors, and start to
     * change in white, beige, crimson, white if the vertex wasn't visited,
     * beije if the vertex was visited, and crimson if all adjacents vertex of a
     * vertex was visited. It's important to observe that evertime that the
     * collor of the vertex change, we put to sleep for some seconds, so we can
     * see the step-by-step.
     *
     * @param g the adjacency list.
     * @param v the vertex.
     */
    public void dfsvisit(GraphList g, Vertice v) {

        String aux = "";
        tempo += 1;
        v.setD(tempo);
        v.setCor("cinza");
        colorir(v.getNome());
        texto += aux.valueOf(v.getNome() + 1) + "; ";
        try {
            if (dimacsFile == false) {
                sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        imprimir(texto + "\n", textoAnterior);
        console.end();
        Adjacencia p = g.getA()[v.getNome()];
        while (p != null) {
            if (p.getDado().getCor().equals("branco")) {
                p.getDado().setPi(v);
                this.dfsvisit(g, p.getDado());
                imprimir(texto + "\n", textoAnterior);
                console.end();
            }
            if (p.getProx() != null) {
                p = p.getProx();
            } else {
                break;
            }
        }
        v.setCor(null);
        tempo += 1;
        v.setF(tempo);
        if (g.getA()[v.getNome()] != null) {
            g.getA()[v.getNome()].getDado().setCor("preto");
        }
        if (vertices.get(tabExecutando).isEmpty() == false && !vertices.get(tabExecutando).get(v.getNome()).getFill().equals(Color.BROWN)) {
            imprimir(texto + "\n", textoAnterior);
            console.end();
            recolorir(v.getNome(), tabExecutando);
            try {
                if (dimacsFile == false) {
                    sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }

    /**
     * method to vertex go beige.
     *
     * @param a integer to represent the vertex.
     */

    public void colorir(int a) {
        if (vertices.get(tabExecutando).isEmpty() == false) {
            Platform.runLater(() -> this.vertices.get(tabExecutando).get(a).setFill(Color.KHAKI));
        }
    }

    /**
     * method to vertex go crimson.
     *
     * @param a index of vertex
     * @param tabExecutando index of the current tab
     */
    public void recolorir(int a, int tabExecutando) {
        if (vertices != null) {
            Platform.runLater(() -> this.vertices.get(tabExecutando).get(a).setFill(Color.color(0.9, 0.1, 0.1)));

        }
    }

    /**
     * method to all vertex go white.
     */
    public void toWhite() {
        if (vertices != null) {
            for (int i = 0; i < vertices.get(tabExecutando).size(); i++) {
                vertices.get(tabExecutando).get(i).setFill(Color.WHITE);
            }
        }

    }

    /**
     * method to print in the console the DFS.
     *
     * @param textoFila append text to add in console.
     * @param textoAnterior keep the previous text in the console.
     */
    public void imprimir(String textoFila, String textoAnterior) {
        if (tabPane.getTabs().get(tabExecutando).isSelected()) {
            Platform.runLater(() -> console.setText(textoAnterior + textoFila + "\n"));
            console.end();
            stringConsole.set(tabExecutando, textoAnterior + textoFila + "\n");
        } else {
            stringConsole.set(tabExecutando, textoAnterior + textoFila + "\n");
        }
    }

}
